describe('cypress 断言示例', () => {
  beforeEach(()=>{
    cy.exec('node main.js',{ failOnNonZeroExit: false })
    cy.visit('http://localhost:3000/demo-get.html');
  })

  // 详见 https://docs.cypress.io/guides/references/assertions

  /**  
   *  to, be, been, is, that, which, and, has, have, with, at, of, same 无意义用以提高断言的可读性。
   *  to：通常用于构建断言的语法结构，例如 cy.get('element').should('be.visible').to.be.true 。
   *  be：用于表示对某个元素的状态或属性的期望，例如 should('be.visible') 表示期望元素可见。
   *  been：在某些上下文可能用于表示已经处于某种状态。
   *  is：类似于 be ，例如 should('is.checked') 表示期望元素被选中。
   *  that：用于引导更复杂的断言条件描述。
   *  which：在特定的断言上下文中用于指定特定的条件或属性。
   *  and：用于连接多个断言条件，例如 should('be.visible').and('have.text', 'Expected Text') 。
   *  has：常用于检查元素是否具有某些属性或特性，如 should('have.class', 'expectedClass') 。
   *  have：类似于 has ，例如 should('have.attr', 'href', 'expectedHref') 。
   *  with：在某些断言中用于提供更详细的条件信息。
   *  at：可能用于指定元素在页面中的位置或索引等条件。
   *  of：用于描述所属关系或范围。
   *  same：通常用于比较两个值是否相同，例如 should('be.same', expectedValue) 。
   *  */ 

  it('拓展库chai(bdd)',()=>{
    /**
     * `not`：用于对后续的断言进行取反。
     * 示例： `expect(5).not.to.equal(10);`
     * 
     * `deep`：通常与其他断言方法结合使用，用于进行深度比较，包括对象内部的嵌套结构。
     * 示例： `expect({ a: { b: 1 } }).to.deep.equal({ a: { b: 1 } });`
     * 
     * `nested`：用于处理嵌套的对象结构断言。
     * 
     * `ordered`：可能用于断言数组元素的顺序。
     * 
     * `any`：表示至少一个元素满足条件。
     * 示例： `expect([1, 2, 3]).to.have.any.members([2, 4]);`
     * 
     * `all`：表示所有元素都满足条件。
     * 示例： `expect([1, 2, 3]).to.all.be.lessThan(4);`
     * 
     * `a(type)`：断言对象的类型。
     * 示例： `expect('hello').to.be.a('string');`
     * 
     * `include(value)`：断言数组包含指定的值。
     * 示例： `expect([1, 2, 3]).to.include(2);`
     * 
     * `ok`：断言值为真。
     * 示例： `expect(true).to.be.ok;`
     * 
     * `true`、`false`：断言值为布尔类型的真或假。
     * 示例： `expect(true).to.be.true;`
     * 
     * `null`、`undefined`：断言值为 `null` 或 `undefined` 。
     * 示例： `expect(null).to.be.null;`
     * 
     * `exist`：断言对象存在（不为 `null` 或 `undefined` ）。
     * 示例： `expect(obj).to.exist;`
     * 
     * `empty`：断言数组或字符串为空。
     * 示例： `expect('').to.be.empty;`
     * 
     * `arguments`：可能用于断言函数的参数。
     * 
     * `equal(value)`：断言值相等（基本类型的严格相等）。
     * 示例： `expect(5).to.equal(5);`
     * 
     * `deep.equal(value)`：深度比较对象或数组是否相等。
     * 示例： `expect({ a: 1 }).to.deep.equal({ a: 1 });`
     * 
     * `eql(value)`：类似于 `equal` ，但对于某些复杂类型可能有不同的行为。
     * 
     * `greaterThan(value)`：断言值大于指定值。
     * 示例： `expect(5).to.be.greaterThan(3);`
     * 
     * `least(value)`：可能是 `atLeast(value)` 的误写，断言值至少等于指定值。
     * 示例： `expect(5).to.be.atLeast(5);`
     * 
     * `lessThan(value)`：断言值小于指定值。
     * 示例： `expect(3).to.be.lessThan(5);`
     * 
     * `most(value)`：可能是 `atMost(value)` 的误写，断言值至多等于指定值。
     * 示例： `expect(3).to.be.atMost(5);`
     * 
     * `within(start, finish)`：断言值在指定的范围内。
     * 示例： `expect(4).to.be.within(3, 5);`
     * 
     * `instanceOf(constructor)`：断言对象是指定构造函数的实例。
     * 示例： `expect(new Date()).to.be.instanceOf(Date);`
     * 
     * `property(name, [value])`：断言对象具有指定名称的属性，可选地检查属性值。
     * 示例： `expect({ name: 'John' }).to.have.property('name', 'John');`
     * 
     * `deep.property(name, [value])`：深度断言对象具有指定名称的属性，包括嵌套对象中的属性。
     * 
     * `ownProperty(name)`：断言对象自身具有指定名称的属性，不包括继承的属性。
     * 
     * `ownPropertyDescriptor(name)`：断言对象自身具有指定名称的属性描述符。
     * 
     * `lengthOf(value)`：断言数组或字符串的长度。
     * 示例： `expect([1, 2, 3]).to.have.lengthOf(3);`
     * 
     * `match(RegExp)`：断言字符串匹配指定的正则表达式。
     * 示例： `expect('hello').to.match(/^h/);`
     * 
     * `string(string)`：断言值为字符串类型且具有指定的内容。
     * 
     * `keys(key1, [key2], [...])`：断言对象具有指定的键。
     * 
     * `throw(constructor)`：断言函数抛出指定类型的错误。
     * 示例： `expect(() => { throw new Error('Error'); }).to.throw(Error);`
     * 
     * `respondTo(method)`：断言对象具有指定的方法。
     * 
     * `itself`：用于进一步描述断言的对象。
     * 
     * `satisfy(method)`：断言对象满足指定的函数条件。
     * 
     * `closeTo(expected, delta)`：断言数值接近指定的值，允许一定的误差范围（`delta`）。
     * 示例： `expect(3.14).to.be.closeTo(3.1415, 0.01);`
     * 
     * `members(set)`：断言数组是指定集合的子集。
     * 
     * `oneOf(values)`：断言值是指定值数组中的一个。
     * 示例： `expect(2).to.be.oneOf([1, 2, 3]);`
     * 
     * `change(function)`：断言函数会导致某个值发生变化。
     * 
     * `increase(function)`：断言函数会导致值增加。
     * 
     * `decrease(function)`：断言函数会导致值减少。
     */ 
  })

  it('拓展库chai(dom操作)',()=>{
    // 判断属性
    cy.get('.box').should('have.attr','data-id')
    cy.get('.box').then(e=>{
      expect(e).to.have.attr('name');
    });
    // cy.get('.box').should('not.attr','data-id')
    
    // 判断class
    cy.get('.box').then(e=>{
      expect(e).to.have.class('other-class-name');
    });

    // 判断id
    cy.get('.txt').should('be.have.id','app-txt');

    // 判断文本 - 直接判断可能因为换行和前后空格,导致异常
    cy.get('.txt').should('have.text','文字')  

    // 包含文本
    cy.get('.txt').should('have.contain','字')  

    // 判断input的值
    cy.get('[type="text"]').first().type('hello world');
    cy.get('[type="text"]').first().should('have.value','hello world');

    // 显示、隐藏
    cy.get('.hide').should('be.hidden');
    cy.get('.txt').should('be.visible');

    // 判断是否为空
    cy.get('.txt').should('not.be.empty');

    // 判断是否禁用
    cy.get('[type="text"]').first().should('to.be.enabled');
    cy.get('[type="text"]').first().should('not.be.disabled');
    cy.get('[type="text"]').last().should('not.be.enabled');
    cy.get('[type="text"]').last().should('to.be.disabled');

    // 判断选中
    cy.get('#select').select('2');
    cy.get('#select .item-2').should('be.selected'); // select 中 option
  })
})